/*
观察者模式角色如下：
抽象主题（Subject）角色：抽象主题角色提供维护一个观察者对象集合的操作方法，对集合的增加、删除等。
具体主题（ConcreteSubject）角色：将有关状态存入具体的观察者对象；在具体主题的内部状态改变时，给所有登记过的观察者发通知。具体主题角色负责实现抽象主题中的方法。
抽象观察者（Observer）角色：为具体观察者提供一个更新接口。
具体观察者（ConcreteObserver）角色：存储与主题相关的自洽状态，实现抽象观察者提供的更新接口。
*/

/* 案例：
在教室里老师还没有来，同学都在干着各的事情，小张正在打游戏，小李正在抄作业.....,  现在同学们要求班长当卧底，监视老师，当老师来了通知大家一声。然后打游戏的马上停止，抄作业的也停止。
这里班长相当于是一个通知者， 小张、小李，以及其他同学显然是监听者，他们监听了班长那的消息，一旦老师来了马上采取相关的行动。
*/


#include <iostream>
#include <memory>
#include <mutex>
#include <list>

using namespace std;

/// 定义一个监听者的接口，想要监听老师来了这个消息的同学必须要实现这个接口
class ITeacherListenner // 所有的监听者都需要继承这个类
{
public:
    ITeacherListenner(){}
    virtual ~ITeacherListenner() {}
    virtual void onTecherComming(int value) = 0;
};

/// 先把通知者的行为抽象为一个接口
class INotifier   // 通知者
{
public:
    INotifier(){}
    virtual ~INotifier() {}
    virtual void registerListenner(std::shared_ptr<ITeacherListenner> pListenner) =0 ;
    virtual void removeListenner(std::shared_ptr<ITeacherListenner> pListenner) =0 ;
    virtual void notify() =0 ;
protected:
    mutable std::mutex m_mtx;
    std::list<std::shared_ptr<ITeacherListenner> > m_listennerList;
};

///  班长作为一个具体的通知者 MonitorNotifier
class MonitorNotifier:public INotifier
{
public:
    void registerListenner(std::shared_ptr<ITeacherListenner> pListenner)
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        m_listennerList.push_back(pListenner);
    }

    void removeListenner(std::shared_ptr<ITeacherListenner> pListenner)
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        m_listennerList.remove(pListenner);
    }

    void notify()
    {
        for (std::shared_ptr<ITeacherListenner> &pListenner : m_listennerList)
        {
            pListenner->onTecherComming(mValue);
        }
    }

    void setValue(int value)
    {
        mValue = value;
        notify();
    }
private:
    int mValue;
};

/// 第四，ZhangSan 和 LiSi 监听了老师来了这个接口：
class ZhangSan:public ITeacherListenner
{
public:
    void onTecherComming(int value)
    {
        stopCopyWork(value);
    }

    void stopCopyWork(int value)
    {
        cout<<"zhangsan stopCopyWork + "<<value<<endl;
    }
};

class LiSi:public ITeacherListenner
{
public:
    void onTecherComming(int value)
    {
        stopPlayGame(value);
    }
    void stopPlayGame(int value)
    {
        cout<<"lisi stopPlayGame + "<<value<<endl;
    }
};


int main()
{
   cout << "Hello World1-------------"<<endl;

   std::shared_ptr<MonitorNotifier> spMonitorNotifier = std::make_shared<MonitorNotifier>();

   std::shared_ptr<ZhangSan> spZhangSan = std::make_shared<ZhangSan>();
   std::shared_ptr<LiSi> spLiSi = std::make_shared<LiSi>();

   spMonitorNotifier->registerListenner(spZhangSan);
   spMonitorNotifier->registerListenner(spLiSi);
   spMonitorNotifier->setValue(1);

   cout << "Hello World2-------------"<<endl;
   spMonitorNotifier->removeListenner(spLiSi);
   spMonitorNotifier->setValue(2);

   return 0;
}
